
/**
* 命名空间: Game.TDBehaviorTree
*
* 功 能： Animator编辑器进行播放
* 类 名： EditorAnimatorPlay
*
* Ver 变更日期 负责人 变更内容
* ───────────────────────────────────
* V0.01 2019/12/13 15:06:51  
*/

using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
using System.Collections.Generic;

namespace Game.TDBehaviorTree
{

	public class EditorAnimatorPlay : EditorWindow
	{

		private List<AnimatorState> stateNames = new List<AnimatorState>();
		private int m_AnimSelectID = 0;
		private GameObject m_GameObjt;
		private Animator m_Animator;
		private AnimatorController m_AnimConS;
		private AnimatorState m_AnimState;

		protected float m_ClipTime = 0.0f;
		private string[] m_AnimSelectStringArray;
		private bool m_PlayTime = false;
		protected bool m_LockSelection = false;
		private bool m_IsBake = false;
		private string m_CurrentState = "";

		/// <summary>
		/// 时间增量
		/// </summary>
		private double m_Delta;

		/// <summary>
		/// 当前运行时间
		/// </summary>
		private float m_RunningTime;

		/// <summary>
		/// 上一次系统时间
		/// </summary>
		private double m_PreviousTime;

		/// <summary>
		/// 最大时间长度	
		/// </summary>
		private float m_AnimTime = 0.0f;

		private float m_RecordEndTime = 0;

		private bool m_IsInspectorUpdate = false;

		private void Init()
		{
			stateNames.Clear();
			m_AnimSelectID = 0;
			m_ClipTime = 0.0f;
			m_AnimSelectStringArray = null;
			m_PlayTime = false;
			m_LockSelection = false;
		}

		[MenuItem("Tools/编辑模式动画播放")]
		public static void DoWindow()
		{
			GetWindow<EditorAnimatorPlay>("编辑模式动画播放");
		}

		public void OnSelectionChange()
		{
			if (!m_LockSelection)
			{
				m_GameObjt = Selection.activeGameObject;
				m_Animator = null;
				if (m_GameObjt != null && m_GameObjt.GetComponent<Animator>() != null)
				{
					Init();
					m_Animator = m_GameObjt.GetComponent<Animator>();
					GetAllStateName();
					SelectStateResume();
					AnimBake(m_AnimState);

				}
				Repaint();
			}
		}

		private void GetAllStateName()
		{
			if (m_Animator != null)
			{
				var runAnimator = m_Animator.runtimeAnimatorController;
				m_AnimConS = runAnimator as AnimatorController;

				foreach (var layer in m_AnimConS.layers)
				{
					GetAnimState(layer.stateMachine);
				}

			}
		}

		private void GetAnimState(AnimatorStateMachine aSM)
		{
			foreach (var s in aSM.states)
			{
				if (s.state.motion == null)
					continue;
				var clip = GetClip(s.state.motion.name);
				if (clip != null)
				{
					stateNames.Add(s.state);
				}
			}

			foreach (var sms in aSM.stateMachines)
			{
				GetAnimState(sms.stateMachine);
			}
		}

		private AnimationClip GetClip(string name)
		{
			foreach (var clip in m_AnimConS.animationClips)
			{
				if (clip.name.Equals(name))
					return clip;
			}

			return null;
		}

		public void OnGUI()
		{

			if (m_GameObjt == null || m_Animator == null)
			{
				EditorGUILayout.HelpBox("请选择一个带Animator的物体！", MessageType.Info);
				return;
			}


			var oldAniID = m_AnimSelectID;
			m_AnimSelectID = EditorGUILayout.Popup("动画列表", m_AnimSelectID, m_AnimSelectStringArray);

			m_AnimState = stateNames[m_AnimSelectID];

			if (oldAniID != m_AnimSelectID)
			{
				m_IsBake = false;
				AnimBake(m_AnimState);
			}

			EditorGUILayout.BeginHorizontal();

			EditorGUI.BeginChangeCheck();
			if (!m_LockSelection)
			{
				m_CurrentState = "开启动画";
			}
			else
			{
				m_CurrentState = "关闭动画";
			}
			GUILayout.Toggle(AnimationMode.InAnimationMode(), m_CurrentState, EditorStyles.toolbarButton);
			if (EditorGUI.EndChangeCheck())
			{
				m_LockSelection = !m_LockSelection;
				if (!m_LockSelection)
				{
					OnClose();
				}
				AnimBake(m_AnimState);
			}
			GUILayout.FlexibleSpace();

			if (GUILayout.Button("Play"))
			{
				m_PlayTime = true;
			}
			if (GUILayout.Button("Stop"))
			{
				m_PlayTime = false;
			}
			EditorGUILayout.EndHorizontal();

			if (m_AnimState != null)
			{
				if (!m_PlayTime)
				{
					float startTime = 0.0f;
					float stopTime = m_RecordEndTime;
					m_ClipTime = EditorGUILayout.Slider(m_ClipTime, startTime, stopTime);
					var zhen = m_ClipTime * 30;
					EditorGUILayout.LabelField("帧数：" + (int)zhen);
				}
			}
			Repaint();
		}

		private void SelectStateResume()
		{
			m_AnimSelectStringArray = new string[stateNames.Count];
			for (int i = 0; i < stateNames.Count; i++)
			{
				m_AnimSelectStringArray[i] = stateNames[i].name;
			}

		}


		/// <summary>
		/// 预览播放状态下的更新
		/// </summary>
		void OnUpdate()
		{
			if (Application.isPlaying || !m_LockSelection)
			{
				return;
			}

			if (m_GameObjt == null)
				return;

			if (m_AnimState == null)
				return;

			if (m_Animator != null && m_Animator.runtimeAnimatorController == null)
				return;

			if (!m_IsBake)
			{
				return;
			}

			if (m_PlayTime)
			{
				if (m_RunningTime <= m_AnimTime)
				{
					m_Animator.playbackTime = m_RunningTime;
					m_Animator.Update(0);
				}
				if (m_RunningTime >= m_AnimTime)
				{
					m_RunningTime = 0.0f;
				}
			}
			else
			{
				m_RunningTime = m_ClipTime;
				m_Animator.playbackTime = m_RunningTime;
				m_Animator.Update(0);
			}
		}

		void OnClose()
		{
			if (m_Animator != null)
			{
				m_RunningTime = 0;
				m_Animator.playbackTime = m_RunningTime;
				m_Animator.Update(0);
			}
		}

		void AnimBake(AnimatorState state)
		{
			if (Application.isPlaying || state == null || !m_LockSelection)
			{
				return;
			}

			m_AnimTime = 0.0f;

			m_AnimTime = GetClip(state.motion.name).length;

			float frameRate = 30f;
			int frameCount = (int)((m_AnimTime * frameRate) + 2);
			m_Animator.StopPlayback();
			m_Animator.Play(state.name);
			m_Animator.recorderStartTime = 0;

			m_Animator.StartRecording(frameCount);

			for (var j = 0; j < frameCount - 1; j++)
			{
				m_Animator.Update(1.0f / frameRate);
			}

			m_Animator.StopRecording();
			m_RecordEndTime = m_Animator.recorderStopTime;
			m_Animator.StartPlayback();
			m_IsBake = true;
		}

		void OnEnable()
		{
			m_PreviousTime = EditorApplication.timeSinceStartup;
			EditorApplication.update += InspectorUpdate;
			m_IsInspectorUpdate = true;
		}

		void OnDestroy()
		{
			EditorApplication.update -= InspectorUpdate;
			m_IsInspectorUpdate = false;
			OnClose();
		}

		private void InspectorUpdate()
		{
			m_Delta = EditorApplication.timeSinceStartup - m_PreviousTime;
			m_PreviousTime = EditorApplication.timeSinceStartup;

			if (!Application.isPlaying)
			{
				m_RunningTime = m_RunningTime + (float)m_Delta;
				OnUpdate();
			}
		}
	}

}
